package com.cloudJeesite.component.gatewayService.filter.xss.requestwrapper;


import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang3.StringUtils;

import com.cloudJeesite.component.gatewayService.filter.xss.utils.GsonUtil;
import com.cloudJeesite.component.gatewayService.filter.xss.utils.JsoupUtil;
import com.cloudJeesite.component.gatewayService.filter.xss.vo.Project;

/**
 * XssRequestWrapper
 * 
 * @author Star.Guo
 *
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
	private boolean isUpData = false;// 判断是否是上传 上传忽略
	private HttpServletRequest orgRequest = null;
	private boolean isIncludeRichText = false;
	private byte[] reqBodyBytes = null;
	private String containKey;
	private String filterPrefix;
	private Project project;
	Map<String, String[]> params = new HashMap<String, String[]>();

	public XssHttpServletRequestWrapper(HttpServletRequest request, boolean isIncludeRichText, String containKey,
			String filterPrefix) {
		super(request);
		orgRequest = request;
		this.isIncludeRichText = isIncludeRichText;
		String contentType = request.getContentType();
		this.containKey = containKey;
		this.filterPrefix = filterPrefix;
		params.putAll(request.getParameterMap());
		if (null != contentType)
			isUpData = contentType.startsWith("multipart");
	}

	/**
	 * 覆盖getParameter方法，将参数名和参数值都做xss过滤。<br/>
	 * 如果需要获得原始的值，则通过super.getParameterValues(name)来获取<br/>
	 * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
	 */
	@Override
	public String getParameter(String name) {
		Boolean flag = name.contains("html");
		if (flag && !isIncludeRichText) {
			return super.getParameter(name);
		}
		name = JsoupUtil.clean(name);
		String value = "";
		Object v = params.get(name);
		if (v == null) {
			return null;
		} else if (v instanceof String[]) {
			String[] strArr = (String[]) v;
			if (strArr.length > 0) {
				return strArr[0];
			} else {
				return null;
			}
		} else if (v instanceof String) {
			value = (String) v;
		} else {
			value = v.toString();
		}
		if (StringUtils.isNotEmpty(value)) {
			value = JsoupUtil.clean(value);
		}
		return value;
	}

	@Override
	public Map<String, String[]> getParameterMap() {
		if(params!=null&&params.size()>0) {
			for (String key : params.keySet()) {
				Boolean flag = key.contains("html");
				if (flag && !isIncludeRichText) {
					continue;
				}
				String[] arr = params.get(key);
				if(arr!=null&&arr.length>0) {
					for (int i = 0; i < arr.length; i++) {
						arr[i] = JsoupUtil.clean(arr[i]);
					}
					params.put(key, arr);
				}
			}
		}
		return params;
	}

	@Override
	public String[] getParameterValues(String name) {
		String[] arr = params.get(name);
		if (arr != null) {
			for (int i = 0; i < arr.length; i++) {
				arr[i] = JsoupUtil.clean(arr[i]);
			}
		}
		return arr;
	}

	/**
	 * 覆盖getHeader方法，将参数名和参数值都做xss过滤。<br/>
	 * 如果需要获得原始的值，则通过super.getHeaders(name)来获取<br/>
	 * getHeaderNames 也可能需要覆盖
	 */
	@Override
	public String getHeader(String name) {
		name = JsoupUtil.clean(name);
		String value = super.getHeader(name);
		if (StringUtils.isNotBlank(value)) {
			value = JsoupUtil.clean(value);
		}
		return value;
	}

	@Override
	public Object getAttribute(String name) {
		Object value = super.getAttribute(name);
		if (null != value && value instanceof String) {
			if (value != null) {
				value = JsoupUtil.clean((String) value);
			}
		}
		return value;
	}

	@Override
	public ServletInputStream getInputStream() throws IOException {
		try {
			if (isUpData) {
				return super.getInputStream();
			} else {

				final ByteArrayInputStream bais = new ByteArrayInputStream(
						inputHandlers(super.getInputStream()).getBytes("utf-8"));

				return new ServletInputStream() {

					@Override
					public int read() throws IOException {
						return bais.read();
					}

					@Override
					public boolean isFinished() {
						return false;
					}

					@Override
					public boolean isReady() {
						return false;
					}

					@Override
					public void setReadListener(ReadListener readListener) {
					}
				};
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public int getContentLength() {
		if (reqBodyBytes != null) {
			// TODO Auto-generated method stub
			return reqBodyBytes.length;
		}
		return super.getContentLength();
	}

	@Override
	public long getContentLengthLong() {
		if (reqBodyBytes != null) {
			// TODO Auto-generated method stub
			return reqBodyBytes.length;
		}
		return super.getContentLengthLong();
	}

	/**
	 * 获取最原始的request
	 * 
	 * @return
	 */
	public HttpServletRequest getOrgRequest() {
		return orgRequest;
	}

	/**
	 * 获取最原始的request的静态方法
	 * 
	 * @return
	 */
	public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
		if (req instanceof XssHttpServletRequestWrapper) {
			return ((XssHttpServletRequestWrapper) req).getOrgRequest();
		}

		return req;
	}

	public void addParameter(String name, Object value) {// 增加参数

		if (value != null) {

			if (value instanceof String[]) {

				params.put(name, (String[]) value);

			} else if (value instanceof String) {

				params.put(name, new String[] { (String) value });

			} else {

				params.put(name, new String[] { String.valueOf(value) });

			}

		}

	}

	public String inputHandlers(ServletInputStream servletInputStream) {
		String newBody = "";
		StringBuilder sb = new StringBuilder();
		BufferedReader reader = null;
		if(servletInputStream==null) {
			return newBody;
		}
		try {
			reader = new BufferedReader(new InputStreamReader(servletInputStream, Charset.forName("UTF-8")));
			String line = "";
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (servletInputStream != null) {
				try {
					servletInputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		if(sb==null||sb.length()<1) {
			return newBody;
		}
		newBody = JsoupUtil.clean(sb.toString());
		if (StringUtils.isNotEmpty(filterPrefix) && orgRequest.getRequestURI().startsWith(filterPrefix)
				&& StringUtils.isNotEmpty(containKey) && newBody.contains(containKey)) {
			project = (Project) GsonUtil.decrypt(newBody, Project.class);
			if (StringUtils.isNotEmpty(project.getProId())) {
				String[] values = { project.getProId() };
				params.put("proId", values);
			}
		}
		if (StringUtils.isNotEmpty(newBody)) {
			reqBodyBytes = newBody.getBytes();
		}
		return newBody;
	}
}